﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using PBO.Data;
using PBO.Data.SQLite;

namespace PBO.Data.Util
{
    public static class PokemonValidator
    {

        #region 6D

        public static bool ValidateIv(this IStats iv)
        {
            return !iv.Any(p => p < 0 || p > 31);
        }

        public static bool ValidateEv(this IStats ev)
        {
            return !ev.Any(p => p < 0 || p > 255) && ev.Sum() <= 510;
        }

        #endregion

        //src\PokemonInfo\pokemoninfo.cpp -> RunMovesSanityCheck

        #region ValidateTeam

        public static void Validate(this TeamData team)
        {
            if (team != null)
            {
                for (int i = 0; i < team.Pokemons.Length; i++)
                {
                    var pm = team.Pokemons[i];
                    if (pm == null || pm.Identity == 0 || !pm.ValidatePokemonInfo())
                    {
                        pm = PokemonCustomInfo.EmptyPokemon;
                        continue;
                    }
                    if (pm.Moves.All(m => m == 0) || !ValidateMoves(pm.Identity, pm.Ability, pm.Moves.Where(m => m > 0).ToArray()))
                    {
                        pm.Moves[0] = SQLiteHelper.MoveLearnData.GetByPid(pm.Identity).First().MoveId;
                        pm.Moves[1] = pm.Moves[2] = pm.Moves[3] = 0;
                    }
                }
                team.Sort();
            }
        }

        #endregion

        #region ValidatePokemonInfo

        /// <summary>
        /// 检查技能共存外的所有参数
        /// </summary>
        internal static bool ValidatePokemonInfo(this PokemonCustomInfo info)
        {
            var data = GameService.GetPokemon(info.Identity);
            if (data == null) return false;

            string name = info.NickName.Trim();
            if (!StringHelper.ValidatePmName(name)) info.NickName = data.NameBase;
            if (!data.Traits.Contains(info.Ability)) info.Ability = data.Traits.First();
            if (!data.Genders.Contains(info.Gender)) info.Gender = data.Genders.First();
            info.LV = Math.Max((byte)1, Math.Min((byte)100, info.LV));
            if (!info.Iv.ValidateIv()) info.Iv.SetAll(31);
            if (!info.Ev.ValidateEv()) info.Ev.SetAll(85);

            //技能 去重&特性共存检查
            var trait = info.Ability;
            var list = SQLiteHelper.MoveLearnData.GetMoves(info.Identity, info.Moves);
            var arr = info.Moves.Where(i => list.Any(m => m.MoveId == i && m.WithoutTrait != trait)).Distinct().ToArray();
            int[] moves = Enumerable.Repeat(0, 4).ToArray();
            for (int i = 0; i < arr.Length; i++)
            {
                moves[i] = arr[i];
            }
            info.Moves = moves;

            return true;
        }

        /// <summary>
        /// 技能共存
        /// </summary>
        public static bool ValidateMoves(int pid, Trait ability, params int[] moves)
        {
            var data = GameService.GetPokemon(pid);
            return CheckMoves(moves, data);
        }

        public static string[] ValidateMoves2(int pid, Trait ability, params int[] moves)
        {


            return null;
        }

        #endregion

        #region Check

        private static string FalseMove1, FalseMove2;

        #region egg group

        public static List<PokemonData> GetEggGroup(EggGroup eggGroup, List<EggGroup> exceptList)
        {
            return (from PokemonData pm in GameService.GetAllPokemons()
                    where ((pm.EggGroup1 == eggGroup && !exceptList.Contains(pm.EggGroup2)) ||
                    (pm.EggGroup2 == eggGroup && !exceptList.Contains(pm.EggGroup1))) &&
                    pm.GenderRestriction != PokemonGenderRestriction.FemaleOnly &&
                    pm.GenderRestriction != PokemonGenderRestriction.NoGender
                    select pm).ToList();
        }

        /// <summary>
        /// 根据PM获取相同蛋组的PM
        /// </summary>
        private static List<PokemonData> GetEggGroup(EggGroup eggGroup, PokemonData except)
        {
            int[] Tyrogue = { 106, 107, 236, 237 };
            //巴尔郎
            if (Tyrogue.Contains(except.Number))
            {
                return Tyrogue.Where(i => i != except.Number).Select(i => GameService.GetPokemon(i)).ToList();
            }

            var array = from PokemonData pm in GameService.GetAllPokemons()
                        where pm.Id != except.Id &&
                        (pm.EggGroup1 == eggGroup || pm.EggGroup2 == eggGroup) &&
                        pm.GenderRestriction != PokemonGenderRestriction.FemaleOnly &&
                        pm.GenderRestriction != PokemonGenderRestriction.NoGender
                        select pm;
            return array.ToList();
        }

        #endregion

        public static List<PokemonData> GetPMs(List<PokemonData> list, params int[] moves)
        {
            var pmids = SQLiteHelper.MoveLearnData.GetLearnPid(EggGroup.无, null, moves);
            return list.Where(p => pmids.Contains(p.Id)).ToList();
        }

        public static bool CheckMoves(int[] moves, PokemonData pm, List<EggGroup> exceptList = null)
        {
            var inheritList = SQLiteHelper.MoveLearnData.GetInheritMoves(pm.Id, moves).Select(m => m.Id).ToArray();

            if (inheritList.Length > 2)
            {
                if (!CanInheritMoves(pm, exceptList, inheritList))
                {
                    var names = inheritList.Take(inheritList.Length - 1).Select(i => GameService.GetMove(i).Name);
                    FalseMove2 = string.Join(",", names.ToArray());
                    FalseMove1 = GameService.GetMove(inheritList.Last()).Name;
                    return false;
                }
            }

            for (int i = 0; i < moves.Length - 1; i++)
            {
                for (int j = i + 1; j < moves.Length; j++)
                {
                    if (!CheckMoves(moves[i], moves[j], pm, exceptList))
                    {
                        FalseMove1 = GameService.GetMove(moves[i]).Name;
                        FalseMove2 = GameService.GetMove(moves[j]).Name;
                        return false;
                    }
                }
            }
            return true;
        }

        public static string[] GetErrorMoves(int[] moves, PokemonData pm, List<EggGroup> exceptList = null)
        {
            var inheritList = SQLiteHelper.MoveLearnData.GetInheritMoves(pm.Id, moves).Select(m => m.Id).ToArray();

            if (inheritList.Length > 2)
            {
                if (!CanInheritMoves(pm, exceptList, inheritList))
                {
                    var names = inheritList.Take(inheritList.Length - 1).Select(i => GameService.GetMove(i).Name);
                    return names.ToArray();
                    //FalseMove2 = string.Join(",", names.ToArray());
                    //FalseMove1 = GameService.GetMove(inheritList.Last()).Name;
                    //return false;
                }
            }

            for (int i = 0; i < moves.Length - 1; i++)
            {
                for (int j = i + 1; j < moves.Length; j++)
                {
                    if (!CheckMoves(moves[i], moves[j], pm, exceptList))
                    {
                        return new string[]
                        {
                            GameService.GetMove(moves[i]).Name,
                            GameService.GetMove(moves[j]).Name
                        };
                    }
                }
            }
            return null;
        }

        #region CheckMoves

        private static bool CheckMoves(int move1, int move2, PokemonData pm, List<EggGroup> exceptList = null)
        {
            var moveData1 = SQLiteHelper.MoveLearnData.GetMove(pm.Id, move1);
            var moveData2 = SQLiteHelper.MoveLearnData.GetMove(pm.Id, move2);
            return CheckMovesSwap(pm, moveData1, moveData2, exceptList) &&
                CheckMovesSwap(pm, moveData2, moveData1, exceptList) &&
                CheckMovesNoSwap(pm, moveData1, moveData2, exceptList);
        }

        private static bool CheckMovesSwap(PokemonData pm, MoveLearnData move1, MoveLearnData move2, List<EggGroup> exceptList = null)
        {
            if (move1.Type == LearnType.遗传 && move2.Type == LearnType.未进化 && move2.Info == "旧版")
            {
                return CheckMoves(move1.MoveId, move2.MoveId, GameService.GetPokemon(pm.BeforeEvolution));
            }
            else if (move1.Type == LearnType.遗传 && move2.Type == LearnType.旧版 && (move1.Info == "DSOnly" || move2.Info == "GC"))
            {
                return false;
            }
            else if (move1.Type == LearnType.NPC && move2.Type == LearnType.遗传)
            {
                return false;
            }
            return true;
        }

        private static bool CheckMovesNoSwap(PokemonData pm, MoveLearnData move1, MoveLearnData move2, List<EggGroup> exceptList = null)
        {
            if (move1.Type == LearnType.未进化 && move2.Type == LearnType.未进化)
            {
                if (pm.Number == 292)
                {
                    if (SQLiteHelper.MoveLearnData.GetMove(pm.BeforeEvolution, move1.MoveId) == null &&
                        SQLiteHelper.MoveLearnData.GetMove(pm.BeforeEvolution, move2.MoveId) == null)
                    {
                        return CheckNijiaMoveDatas(move1.MoveId, move2.MoveId);
                    }
                }
                else
                {
                    return CheckMoves(move1.MoveId, move2.MoveId, GameService.GetPokemon(pm.BeforeEvolution));
                }
            }
            else if (move1.Type == LearnType.遗传 && move2.Type == LearnType.遗传)
            {
                return CanInheritMoves(move1.MoveId, move2.MoveId, pm, exceptList);
            }
            return true;
        }

        #endregion

        private static bool CanInheritMoves(int move1, int move2, PokemonData pm, List<EggGroup> exceptList)
        {
            if (pm.EggGroup1 == EggGroup.陆上 || pm.EggGroup2 == EggGroup.陆上) return true;
            if (exceptList == null)
                exceptList = new List<EggGroup>();

            if (exceptList.Contains(pm.EggGroup1) && (exceptList.Contains(pm.EggGroup2) || pm.EggGroup2 == EggGroup.无))
            {
                return false;
            }
            else if (exceptList.Contains(pm.EggGroup1) || exceptList.Contains(pm.EggGroup2))
            {
                EggGroup eggGroup = exceptList.Contains(pm.EggGroup1) ? pm.EggGroup2 : pm.EggGroup1;

                if (eggGroup != EggGroup.无)
                {
                    exceptList.Add(eggGroup);

                    List<PokemonData> list = GetPMs(GetEggGroup(eggGroup, exceptList), move1, move2);

                    foreach (PokemonData inheritPM in list)
                    {
                        if (CheckMoves(move1, move2, inheritPM, exceptList))
                        {
                            return true;
                        }
                    }
                }
            }
            else
            {
                List<PokemonData> list1 = GetPMs(GetEggGroup(pm.EggGroup1, pm), move1, move2);

                exceptList.AddRange(pm.EggGroups);

                foreach (PokemonData inheritPM in list1)
                {
                    if (CheckMoves(move1, move2, inheritPM, exceptList))
                    {
                        return true;
                    }
                }

                if (pm.EggGroup2 != EggGroup.无)
                {
                    var list2 = GetPMs(GetEggGroup(pm.EggGroup2, exceptList), move1, move2);
                    foreach (PokemonData inheritPM in list2)
                    {
                        if (CheckMoves(move1, move2, inheritPM, exceptList))
                        {
                            return true;
                        }
                    }
                }

            }
            return false;
        }

        private static bool CanInheritMoves(PokemonData pm, List<EggGroup> exceptList, params int[] moves)
        {
            if (pm.EggGroups.Contains(EggGroup.陆上)) return true;

            if (exceptList == null) exceptList = new List<EggGroup>();
            if (exceptList.Any(e => pm.EggGroups.Contains(e))) return false;

            if (exceptList.Contains(pm.EggGroup1) && (exceptList.Contains(pm.EggGroup2) || pm.EggGroup2 == EggGroup.无))
            {
                return false;
            }
            else if (exceptList.Contains(pm.EggGroup1))
            {
                if (pm.EggGroup2 != EggGroup.无)
                {
                    exceptList.Add(pm.EggGroup2);

                    var list = GetPMs(GetEggGroup(pm.EggGroup2, exceptList), moves);
                    foreach (PokemonData inheritPM in list)
                    {
                        if (CheckMoves(moves, inheritPM, exceptList))
                        {
                            return true;
                        }
                    }
                }
            }
            else if (exceptList.Contains(pm.EggGroup2))
            {
                exceptList.Add(pm.EggGroup1);

                List<PokemonData> list = GetPMs(GetEggGroup(pm.EggGroup1, exceptList), moves);
                foreach (PokemonData inheritPM in list)
                {
                    if (CheckMoves(moves, inheritPM, exceptList))
                    {
                        return true;
                    }
                }
            }
            else
            {
                exceptList.AddRange(pm.EggGroups);

                var list1 = GetPMs(GetEggGroup(pm.EggGroup1, pm), moves);
                foreach (PokemonData inheritPM in list1)
                {
                    if (CheckMoves(moves, inheritPM, exceptList))
                    {
                        return true;
                    }
                }

                if (pm.EggGroup2 != EggGroup.无)
                {
                    var list2 = GetPMs(GetEggGroup(pm.EggGroup2, exceptList), moves);
                    foreach (PokemonData inheritPM in list2)
                    {
                        if (CheckMoves(moves, inheritPM, exceptList))
                        {
                            return true;
                        }
                    }
                }

            }
            return false;
        }

        /// <summary>
        /// 检查脱壳忍者技能
        /// </summary>
        private static bool CheckNijiaMoveDatas(int id1, int id2)
        {
            var move1 = SQLiteHelper.MoveLearnData.GetMove(292, id1);
            var move2 = SQLiteHelper.MoveLearnData.GetMove(292, id2);
            if (string.IsNullOrEmpty(move1.Info) || string.IsNullOrEmpty(move2.Info)) return true;
            int lv1 = 0;
            int lv2 = 0;
            lv1 = Convert.ToInt32(move1.Info);
            lv2 = Convert.ToInt32(move2.Info);
            return lv1 == lv2;
        }

        public static string CheckTrait(int pid, Trait ability, params int[] moves)
        {
            var move = SQLiteHelper.MoveLearnData.GetWithoutTrait(pid, ability, moves);
            return move == null ? string.Empty : GameService.GetMove(move.MoveId).Name;
        }

        #endregion

    }
}
